﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Reflection;
using System.CodeDom;
using System.ComponentModel.Design;

namespace MvcImproved.Generic
{
	public class GenericPageBuilder : FileLevelPageControlBuilder, IGenericControlBuilder
	{
		/*public override Type GetChildControlType(string tagName, IDictionary attribs)
		{
			Type type = base.GetChildControlType(tagName, attribs);
			GenericControlTypeAttribute data = type.GetCustomAttributes(typeof(GenericControlTypeAttribute), true).Cast<GenericControlTypeAttribute>().FirstOrDefault();
			if (data != null)
			{
				List<Type> genericArgList;
				if (attribs.Contains(data.GenericParameters))
				{
					genericArgList = data.GenericArgumentList(attribs);
				}
				else //Otherwise, try to get the type from the model type 
				{
					genericArgList = new List<Type>();
					genericArgList.Add(ControlType.GetGenericArguments()[0]);
				}
				string lambdaMemberAccess;
				genericArgList.Add(data.GetMemberAccess(genericArgList[genericArgList.Count - 1], attribs, out lambdaMemberAccess));
				type = data.GenericControl.MakeGenericType(genericArgList.ToArray());
			}

			return type;
		}*/

		public string PageBaseTypeName
		{
			get;
			set;
		}

		private static PropertyInfo BaseTypeMember = typeof(TemplateParser).GetProperty("BaseType", BindingFlags.Instance | BindingFlags.NonPublic);
		private static FieldInfo PageParserFilter = typeof(TemplateParser).GetField("_pageParserFilter", BindingFlags.Instance | BindingFlags.NonPublic);

		public override void Init(TemplateParser parser, ControlBuilder parentBuilder, Type type,
			string tagName, string id, IDictionary attribs)
		{
			base.Init(parser, parentBuilder, type, tagName, id, attribs);

			GenericPageParser parserFilter = PageParserFilter.GetValue(parser) as GenericPageParser;
			if ((parserFilter != null) && (parserFilter._GenericData != null))
			{
				GenericControlTypeAttribute data = parserFilter._GenericData;
				// Set the base type to the generic type
				type = data.GenericControl.MakeGenericType(data.GenericArgumentList(parserFilter._GenericParameters, InDesigner, ServiceProvider).ToArray());

				BaseTypeMember.SetValue(parser, type, null);
			}
		}

		public override void ProcessGeneratedCode(
			CodeCompileUnit codeCompileUnit,
			CodeTypeDeclaration baseType,
			CodeTypeDeclaration derivedType,
			CodeMemberMethod buildMethod,
			CodeMemberMethod dataBindingMethod)
		{
			// Use a base class string if one was specified by the GenericPageParser
			if (PageBaseTypeName != null)
			{
				derivedType.BaseTypes[0] = new CodeTypeReference(PageBaseTypeName);
			}

			base.ProcessGeneratedCode(codeCompileUnit, baseType, derivedType, buildMethod, dataBindingMethod);
		}
	}

	// Non-generic version of the control that's used in the actual markup
	[FileLevelControlBuilder(typeof(GenericPageBuilder))]
	[GenericControlType(typeof(System.Web.Mvc.ViewPage<>), GenericParameters = "ModelType")]
	public class ViewPage : System.Web.Mvc.ViewPage<object>
	{
		public string ModelType
		{
			get;
			set;
		}
	}
}
